import json
import os
import socket
import ssl
import sys

from Tkinter import *

tivo_addr = 'tivo address'
mak = 'your mak'

rpc_id = 0
programpath = sys.path[0]
remoteimagepath = os.path.join(programpath, "Assets", "Gifs", "Remote")

def MakeButton(button_name, button_img, img_file, color_name, command_name, x_pos, y_pos):
    button_img = PhotoImage(file = os.path.join(remoteimagepath, img_file))
    button_name = Button(pane,
                         bd=-1,
                         image=button_img,
                         bg=color_name,
                         activebackground=color_name,
                         command= lambda
                         key = command_name :
                         remote.Key(key))
    button_name.image = button_img
    button_name.place(relx=1, x=x_pos, y=y_pos, anchor=N)

def MakeSpecialButton(button_name, button_img, img_file, color_name, command_name, x_pos, y_pos):
    button_img = PhotoImage(file = os.path.join(remoteimagepath, img_file))
    button_name = Button(pane,
                         bd=-1,
                         image=button_img,
                         bg=color_name,
                         activebackground=color_name,
                         command= lambda
                         uri = command_name :
                         remote.uiNavigate(uri))
    button_name.image = button_img
    button_name.place(relx=1, x=x_pos, y=y_pos, anchor=N)

def RpcRequest(type, monitor=False, **kwargs):
    global rpc_id
    rpc_id += 1
    req = dict(**kwargs)
    req.update({'type': type})
    obj = {
        'type': 'mindRpcRequest',
        'request': req,
        'rpcId': rpc_id,
        'mindVersion': 7,
        'monitorFutureChanges': monitor,
        }
    return obj

class Remote(object):
    def __init__(self):
        self.buf = ''
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.ssl_socket = ssl.wrap_socket(self.socket)
        self.ssl_socket.connect((tivo_addr, 1393))
        self.Auth()

    def Read(self):
        while True:
            buf = self.ssl_socket.read(128)
            self.buf += buf
            if '\x00' in buf:
                break

        strs = self.buf.split('\x00', 1)
        # logging.info('READ %s', strs[0])
        obj = json.loads(strs[0])
        self.buf = strs[1]
        return obj

    def Write(self, obj):
        str = json.dumps(obj)
        # logging.info('SEND %s', str)
        self.ssl_socket.send(str + '\x00')

    def Auth(self):
        self.Write(RpcRequest('bodyAuthenticate',
                   credential={
                               'type': 'makCredential',
                                'key': mak,
            }))
        result = self.Read()
        if result['response']['status'] != 'success':
            logging.error('Authentication failed!  Got: %s', result)
            sys.exit(1)

    def Key(self, key):
        if key == ' ':
            key = 'forward'
        if key.lower() in 'abcdefghijklmnopqrstuvwxyz':
            req = RpcRequest('keyEventSend', event='ascii', value=ord(key))
        elif key in '0123456789':
            req = RpcRequest('keyEventSend', event='num' + key)
        else:
            req = RpcRequest('keyEventSend', event=key)

        self.Write(req)

    def Keyboard(self, event):
        if event.char == event.keysym:
            self.Key(event.keysym)
        elif event.keysym in 'Up Down Left Right':
            self.Key(event.keysym.lower())
        else:
            if event.keysym == 'Return':
                self.Key('select')
            if event.keysym == 'BackSpace' or event.keysym == 'Delete':
                self.Key('reverse')
            if event.keysym == 'space':
                self.Key('forward')
            if event.keysym == 'Prior':
                self.Key('channelUp')
            if event.keysym == 'Next':
                self.Key('channelDown')
            if event.keysym == 'Home':
                self.Key('advance')
            if event.keysym == 'End':
                self.Key('replay')
            if event.keysym == 'Escape':
                self.Key('clear')

    def uiNavigate(self, uri):
        req = RpcRequest('uiNavigate',
                         uri='x-tivo:hme:uuid:%s' % uri,
                         bodyId='-')
        self.Write(req)

remote = Remote()
root = Tk()
root.geometry('295x811-1+%d' % int((root.winfo_screenheight()-811)/2))
root.title('YATR - Yet Another TiVo Remote')
root.resizable(FALSE,FALSE)
root.bind_all('<Key>', remote.Keyboard)

pane = Frame(root)
pane.pack()

BaseRemoteImg = PhotoImage(file = os.path.join(remoteimagepath, 'label background.gif'))
BaseRemote = Label(pane,image=BaseRemoteImg,bg='black').pack()

MakeButton('ActionAButton', 'ActionAButtonImg', 'button Action A.gif', 'gray12', 'actionA', -222, 565)
MakeButton('ActionBButton', 'ActionBButtonImg', 'button Action B.gif', 'gray12', 'actionB', -173, 576)
MakeButton('ActionCButton', 'ActionCButtonImg', 'button Action C.gif', 'gray11', 'actionC', -122, 576)
MakeButton('ActionDButton', 'ActionDButtonImg', 'button Action D.gif', 'gray11', 'actionD', -73, 565)
MakeButton('AdvanceButton', 'AdvanceButtonImg', 'button advance.gif', 'gray11', 'advance', -65, 508)
MakeButton('ChanDownButton', 'ChanDownButtonImg', 'button channel down.gif', 'gray11', 'channelDown', -63, 275)
MakeButton('ChanUpButton', 'ChanUpButtonImg', 'button channel up.gif', 'gray11', 'channelUp', -50, 212)
MakeButton('ClearButton', 'ClearButtonImg', 'button clear.gif', 'gray11', 'clear', -213, 747)
MakeButton('DownButton', 'DownButtonImg', 'button down.gif', 'gray24', 'down', -147, 241)
MakeButton('EnterButton', 'EnterButtonImg', 'button enter.gif', 'gray11', 'enter', -81, 747)
MakeButton('FFButton', 'FFButtonImg', 'button forward.gif', 'gray25', 'forward', -77, 432)
MakeButton('GuideButton', 'GuideButtonImg', 'button guide.gif', 'gray11', 'guide', -45, 159)
MakeButton('InfoButton', 'InfoButtonImg', 'button info.gif', 'gray10', 'info', -57, 108)
MakeButton('LeftButton', 'LeftButtonImg', 'button left.gif', 'gray21', 'left', -197, 184)
MakeButton('LiveTVButton', 'LiveTVButtonImg', 'button livetv.gif', 'gray10', 'liveTv', -80, 62)
MakeButton('PauseButton', 'PauseButtonImg', 'button pause.gif', 'gray24', 'pause', -147, 407)
MakeButton('PlayButton', 'PlayButtonImg', 'button play.gif', 'gray24', 'play', -144, 368)
MakeButton('RecButton', 'RecButtonImg', 'button record.gif', 'gray11', 'record', -147, 303)
MakeButton('ReplayButton', 'ReplayButtonImg', 'button replay.gif', 'gray15', 'replay', -230, 508)
MakeButton('REWButton', 'REWButtonImg', 'button reverse.gif', 'gray22', 'reverse', -216, 432)
MakeButton('RightButton', 'RightButtonImg', 'button right.gif', 'gray25', 'right', -96, 185)
MakeButton('SelectButton', 'SelectButtonImg', 'button select.gif', 'gray24', 'select', -147, 190)
MakeButton('SlowButton', 'SlowButtonImg', 'button slow.gif', 'gray24', 'slow', -144, 497)
MakeButton('ThumbsDownButton', 'ThumbsDownButtonImg', 'button thumbsdown.gif', 'gray15', 'thumbsDown', -226, 328)
MakeButton('ThumbsUpButton', 'ThumbsUpButtonImg', 'button thumbsup.gif', 'gray11', 'thumbsUp', -69, 328)
MakeButton('TiVoButton', 'TiVoButtonImg', 'button tivo.gif', 'gray35', 'tivo', -147, 51)
MakeButton('UpButton', 'UpButtonImg', 'button up.gif', 'gray24', 'up', -147, 129)
MakeButton('ZoomButton', 'ZoomButtonImg', 'button zoom.gif', 'gray13', 'zoom', -220, 270)
MakeButton('ZeroButton', 'ZeroButtonImg', 'button 0.gif', 'gray11', '0', -147, 757)
MakeButton('OneButton', 'OneButtonImg', 'button 1.gif', 'gray13', '1', -227, 616)
MakeButton('TwoButton', 'TwoButtonImg', 'button 2.gif', 'gray11', '2', -147, 626)
MakeButton('ThreeButton', 'ThreeButtonImg', 'button 3.gif', 'gray11', '3', -68, 616)
MakeButton('FourButton', 'FourButtonImg', 'button 4.gif', 'gray11', '4', -223, 659)
MakeButton('FiveButton', 'FiveButtonImg', 'button 5.gif', 'gray11', '5', -147, 669)
MakeButton('SixButton', 'SixButtonImg', 'button 6.gif', 'gray11', '6', -73, 659)
MakeButton('SevenButton', 'SevenButtonImg', 'button 7.gif', 'gray11', '7', -218, 702)
MakeButton('EightButton', 'EightButtonImg', 'button 8.gif', 'gray11', '8', -147, 712)
MakeButton('NineButton', 'NineButtonImg', 'button 9.gif', 'gray11', '9', -77, 702)

MakeSpecialButton('OnDemandButton',
                  'OnDemandButtonImg',
                  'button ondemand.gif',
                  'gray13',
                  '6784571A-016C-8A46-DF2F-FD842D78006F',
                  -214, 62)
MakeSpecialButton('AmazonButton',
                  'AmazonButtonImg',
                  'button amazon.gif',
                  'gray10',
                  '35FE011C-3850-2228-FBC5-1B9EDBBE5863',
                  -237, 108)
MakeSpecialButton('BlockbusterButton',
                  'BlockbusterButtonImg',
                  'button blockbuster.gif',
                  'gray10',
                  '63ED0C3D-D49C-9602-C322-E0A3D3EA5A3D',
                  -250, 218)
MakeSpecialButton('NetflixButton',
                  'NetflixButtonImg',
                  'button netflix.gif',
                  'gray10',
                  '7edeb291-0db8-487f-b842-6b97bc71ad9a',
                  -252, 161)

ChanLabelImg = PhotoImage(file = os.path.join(remoteimagepath, 'label channel mid.gif'))
ChanLabel = Label(pane,
                      bd=-1,
                      image=ChanLabelImg,
                      bg='gray11')
ChanLabel.image = ChanLabelImg
ChanLabel.place(relx=1, x=-62, y=245, anchor=N)

mainloop()